﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using SystemX.Infrastructure;
using System.Text;

namespace SystemX
{
	public partial class ObjectX
	{
		/// <summary>
		/// Add a string dictionary entry,and invoke a specified callback action
		/// </summary>
		/// <param name="dic"></param>
		/// <param name="key"></param>
		/// <param name="val"></param>
		/// <param name="onAdded"></param>
		/// <returns></returns>
		public static StringDictionary AddStringDicEntry(this StringDictionary dic, string key, string val, Action<StringDictionary> onAdded)
		{
			if (!dic.ContainsKey(key))
			{
				dic.Add(key, val);
			}
			else
			{
				dic[key] = val;
			}
			if (onAdded != null)
			{
				onAdded(dic);
			}
			return dic;
		}
		/// <summary>
		/// Add a dictionary entry,and invoke a specified callback action 
		/// </summary>
		/// <typeparam name="K"></typeparam>
		/// <typeparam name="V"></typeparam>
		/// <param name="dic"></param>
		/// <param name="key"></param>
		/// <param name="val"></param>
		/// <param name="onAdded"></param>
		public static void AddDicEntry<K, V>(this Dictionary<K, V> dic, K key, V val, Action<Dictionary<K, V>> onAdded)
		{
			dic.Add(key, val);
			if (onAdded != null)
			{
				onAdded(dic);
			}
		}
		/// <summary>
		/// get a value of specified key from a StringDictionry object like StringDictionary
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="dic"></param>
		/// <param name="key"></param>
		/// <param name="defaultVal"></param>
		/// <returns></returns>
		public static T GetAs<T>(this StringDictionary dic,string key, T defaultVal) {
			if (dic == null) return defaultVal;
			if (!dic.ContainsKey(key)) return defaultVal;
			var obj = dic[key].As<T>();
			if (obj.IsDefault<T>()) return defaultVal;
			return obj;
		}
		/// <summary>
		/// get a value of specified key from a StringDictionry object like StringDictionary.
		/// Return default(T) if no such key
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="dic"></param>
		/// <param name="key"></param>
		/// <param name="defaultVal"></param>
		/// <returns></returns>
		public static T GetAs<T>(this StringDictionary dic, string key)
		{
			return dic.GetAs<T>(key, default(T));
		}
        /// <summary>
        /// Serialize a StringDictionary to a json string.
        /// By default,if u use ToJSONStr to do this job,the json string won't be in your wanted format...
        /// Use this method instead of ToJSONStr or ToJSONStr1!
        /// </summary>
        /// <param name="dic"></param>
        /// <param name="ignoreKeys"></param>
        /// <returns></returns>
        /// <remarks>ToJSONStr will provide you [{Key:'xx',Value:'yy'},{Key:'zz',Value:'tt'}] like json str.</remarks>
        public static string ToJSON(this StringDictionary dic, params string[] ignoreKeys)
        {
            if (dic==null||dic.Count==0) return "{}";
            StringBuilder sb = new StringBuilder();
            sb.Append("{");
            foreach(DictionaryEntry i in dic){
                if (ignoreKeys.Contains(i.Key.ToString())) continue;
                sb.AppendFormat("\"{0}\":\"{1}\"", i.Key, i.Value);
            }
            sb.Append("}");
            return sb.ToString();
        }

		#region NameValueCollection ext
		/// <summary>
		/// get a value of specified key from a NameValueCollection object like StringDictionary
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="dic"></param>
		/// <param name="key"></param>
		/// <param name="defaultVal"></param>
		/// <returns></returns>
		public static T GetAs<T>(this NameValueCollection dic, string key, T defaultVal)
		{
			if (dic == null) return defaultVal;
			if (!dic.AllKeys.Contains(key)) return defaultVal;
			var obj = dic[key].As<T>();
			if (obj.IsDefault<T>()) return defaultVal;
			return obj;
		}
		/// <summary>
		/// get a value of specified key from a NameValueCollection object like StringDictionary.
		/// Return default(T) if no such key
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="dic"></param>
		/// <param name="key"></param>
		/// <param name="defaultVal"></param>
		/// <returns></returns>
		public static T GetAs<T>(this NameValueCollection dic, string key)
		{
			return dic.GetAs<T>(key, default(T));
		}
		/// <summary>
		/// Convert the a NameValueCollection  to a SerializableStringDictionary
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
		public static SerializableStringDictionary ToStrDic(this NameValueCollection rawDic, params string[]  ignoreKeys)
		{
			var dic = new SerializableStringDictionary();
			//fastest way to look through the dictionary.
			//http://dotnetperls.com/querystring-net
			if (rawDic.HasKeys())
			{
				for (int i = 0; i < rawDic.Count; i++)
				{
					if (ignoreKeys != null && ignoreKeys.Contains(rawDic.GetKey(i),StringComparer.OrdinalIgnoreCase)) {
						continue;
					}
					dic.Add(rawDic.GetKey(i), rawDic.Get(i));
				}
			}
			return dic;
		}
        /// <summary>
        /// Serialize a nameValueCollection to a json string.
        /// By default,if u use ToJSONStr to do this job,the json string won't be in correct format...
        /// Use this method instead of ToJSONStr or ToJSONStr1!
        /// </summary>
        /// <param name="dic"></param>
        /// <param name="ignoreKeys"></param>
        /// <returns></returns>
        public static string ToJSON(this NameValueCollection dic, params string[] ignoreKeys) {
            if (dic==null||(!dic.HasKeys())) return "{}";
            StringBuilder sb = new StringBuilder();
            sb.Append("{");
            for (int i = 0; i < dic.Count; i++)
            {
                if (ignoreKeys != null && ignoreKeys.Contains(dic.GetKey(i), StringComparer.OrdinalIgnoreCase))
                {
                    continue;
                }
                sb.AppendFormat("\"{0}\":\"{1}\"", dic.GetKey(i), dic.Get(i));
            }
            sb.Append("}");
            return sb.ToString();
        }
        public static string ToQueryString(this NameValueCollection queryString)
        {
            if (queryString.Count > 0)
            {
                StringBuilder qs = new StringBuilder();

                qs.Append("?");

                for (int i = 0; i < queryString.Count; i++)
                {
                    if (i > 0)
                        qs.Append("&");

                    qs.AppendFormat("{0}={1}", queryString.Keys[i], queryString[i]);
                }

                return qs.ToString();
            }

            return "";
        }
		#endregion

		/// <summary>
		/// get a value of specified key from an IDictionary object like StringDictionary
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="dic"></param>
		/// <param name="key"></param>
		/// <param name="defaultVal"></param>
		/// <returns></returns>
		public static T GetAs<T>(this IDictionary dic, object key, T defaultVal)
		{
			if (dic == null) return defaultVal;
			if (!dic.Contains(key)) return defaultVal;
			var obj = dic[key].As<T>();
			if (obj.IsDefault<T>()) return defaultVal;
			return obj;
		}
		/// <summary>
		/// get a value of specified key from an IDictionary object like StringDictionary.
		/// Return default(T) if no such key
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="dic"></param>
		/// <param name="key"></param>
		/// <param name="defaultVal"></param>
		/// <returns></returns>
		public static T GetAs<T>(this IDictionary dic, object key)
		{
			return dic.GetAs<T>(key, default(T));
		}

	}
}
